﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace EpiMapit.Test
{
    [TestClass]
    public class CaseSetAccumulatorFixture
    {

        [TestMethod]
        public void Test1()
        {
            var original = new CaseSetGroup();
            original.Add(
                new CaseSet() { 
                    RegionCode = "Argentina", 
                    Date = new DateTime(2009, 1, 1), 
                    Levels = Cases("A", 1, "B", 2, "C", 3) });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(original, result);
        }

        [TestMethod]
        public void Test2()
        {
            var original = new CaseSetGroup();
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 2, "B", 4, "C", 6)
               });

            var expected = new CaseSetGroup();
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 3, "B", 6, "C", 9)
               });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(expected, result);
        }

        [TestMethod]
        public void Test3()
        {
            var original = new CaseSetGroup();
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 2, "B", 4, "C", 6)
               });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 6, "B", 4, "C", 2)
               });

            var expected = new CaseSetGroup();
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 3, "B", 6, "C", 9)
               });
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 9, "B", 6, "C", 3)
               });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(expected, result);
        }

        [TestMethod]
        public void Test4()
        {
            var original = new CaseSetGroup();
            
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 2, "B", 4, "C", 6)
               });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 6, "B", 4, "C", 2)
               });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });

            var expected = new CaseSetGroup();
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 3, "B", 6, "C", 9)
               });
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 9, "B", 6, "C", 3)
               });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(expected, result);
        }

        [TestMethod]
        public void Test5()
        {
            var original = new CaseSetGroup();
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 6, "B", 4, "C", 2)
               });

            var expected = new CaseSetGroup();
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 1, "B", 2, "C", 3)
               });
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 9, "B", 6, "C", 3)
               });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(expected, result);
        }

        [TestMethod]
        public void Test6()
        {
            var original = new CaseSetGroup();
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 2),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 6, "B", 4, "C", 2)
               });

            var expected = new CaseSetGroup();
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 1, "B", 2, "C", 3)
               });
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 9, "B", 6, "C", 3)
               });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(expected, result);
        }

        [TestMethod]
        public void Test7()
        {
            var original = new CaseSetGroup();
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 3),
                    Levels = Cases("A", 10, "B", 20, "C", 30)
                });
            original.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            original.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 6, "B", 4, "C", 2)
               });

            var expected = new CaseSetGroup();
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Argentina",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 1, "B", 2, "C", 3)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 1, "B", 2, "C", 3)
               });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Argentina",
                   Date = new DateTime(2009, 1, 3),
                   Levels = Cases("A", 11, "B", 22, "C", 33)
               });
            expected.Add(
                new CaseSet()
                {
                    RegionCode = "Brazil",
                    Date = new DateTime(2009, 1, 1),
                    Levels = Cases("A", 3, "B", 2, "C", 1)
                });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 2),
                   Levels = Cases("A", 9, "B", 6, "C", 3)
               });
            expected.Add(
               new CaseSet()
               {
                   RegionCode = "Brazil",
                   Date = new DateTime(2009, 1, 3),
                   Levels = Cases("A", 9, "B", 6, "C", 3)
               });

            var accum = new CaseSetAccumulator();
            var result = accum.Transform(original);

            AssertAreEqual(expected, result);
        }

        private void AssertAreEqual(CaseSetGroup expected, CaseSetGroup actual)
        {
            Assert.AreEqual(expected.Count, actual.Count);

            for (int i = 0; i < expected.Count; i++)
            {
                AssertAreEqual(expected[i], actual[i]);
            }
        }

        private void AssertAreEqual(CaseSet expected, CaseSet actual)
        {
            Assert.AreEqual(expected.RegionCode, actual.RegionCode);
            Assert.AreEqual(expected.Date, actual.Date);
            AssertAreEqual(expected.Levels, actual.Levels);
        }

        private static Dictionary<string, int> Cases(params object[] values) 
        {
            Assert.IsTrue(values.Length % 2 == 0);

            Dictionary<string, int> dictionary = new Dictionary<string,int>();

            for (int i = 0; i < values.Length; i+=2)
            {
                string name = (string)values[i];
                int value = (int)values[i+1];

                dictionary.Add(name, value);
            }

            return dictionary;
        }

        private static void AssertAreEqual(Dictionary<string, int> expected, Dictionary<string, int> actual) 
        {
            Assert.AreEqual(expected.Count, actual.Count);

            foreach (var entry in expected)
            {
                Assert.AreEqual(entry.Value, actual[entry.Key]);
            }

            foreach (var entry in actual)
            {
                Assert.AreEqual(entry.Value, expected[entry.Key]);
            }
        }

    }
}
